moddbfandomcom-20200213-history
RPG MAP2
How we build our maps Prerequisites # Read RPG Map tutorial # Knowledge of your preferred language # Ability to draw images with your chosen language/API # Know how to do basic reading and writing to files Introduction This tutorial is more of an expansion on the previously written RPG Map tutorial. In this tutorial you will be guided on how to make your own map editor, though I think it's all common sense. With the map editor you will load and save maps. It's best to use binary files, but we're still learning here. At the end you will be able to view your map data with your favorite text editor and be able to look at it and say "Oh! That makes perfect sense..." Enjoy. Further map understanding So we've already discussed the map and how it's a 2D array, or matrix, of tiles. Also in the previous tutorial we drew the same image for each tile, and every tile was exactly identical. That is if you didn't play with the code (which you should have!). If you thought it through and visualized what was happening with each line of code, your imagination might give you the following illustration: We draw each column of tiles vertically as we move across the 2D array horizontally. This is because in our loops the Y loop is nested inside the X loop. Hopefully you understand this now from the illustration above. What's this got to do with building maps? Because order is everything. If we changed around the order in which we drew our tiles then it wouldn't be pretty. Your map would be a mess. So keep this in mind: The order in which we load and save and draw our tiles must remain the same. You don't necessarily have to follow my own order, but you must be consistent. Building our map editor Personally, I'm more comfortable with building the map editor to a game before building the actual game. So we need our map editor to do two things for now to make a simple map: set each tile's coordinates for the bitmap (surface coordinates) and make the tile walkable or blocked. With these two objectives in mind, we can plan our map editor. I recommend using a high level language like Visual Basic to put a map editor together quickly. For the user interface we need our tiles bitmap showing for selecting tiles from and we need a place to specifiy map properties, like map width and map height. In addition we need a way to specify whether a tile is blocked; easily done by using left mouse click for walkable tile and right click for blocked tiles. And don't forget the most important part--the map--which will occupy most of the space. In your code we have the tile structure, map array (dynamic), and a rectangle representing which tile we've selected from the bitmap. You can optionally use the camera. If you're using VB, you can put a picturebox inside a picturebox to get the same effect of the camera we made in the previous tutorial. If you can't do something like this, use the camera idea and remember to subtract the camera values when drawing. So now you've got your mental map of what does what with the editor: * There's a way to modify the map size (width and height) before starting to draw tiles, like dialogs prompting the user for parameters * When clicking to place a tile, the sX and sY values of the tile are set to the X and Y coordinates of the tile selection rectangle * There's a way to switch a tile's bBlocked value to true or false, like left sets it false (default) and right click sets it true * And then of course our editor must be able to save and load maps Some helpful information to know when determining which tile has been clicked: Tile X = mouseX - (mouseX mod TileWidth) Tile Y = mouseY - (mouseY mod TileHeight) This is like 'snapping' to the tile grid. If you can imagine that, good. Tile X and Tile Y are now multiples of TileWidth and TileHeight. The mod operator returns the remainder when dividing mouseX by TileWidth, like the % does in C/C++. Make sense? Good. Thats more oriented with the tile selection rectangle. To just get the X and Y values of the tile for referencing the tile in the map array, divide by the TileWidth and TileHeight. Of course if it doesn't round the decimal down then you'll have to use the 'snap' method and divide that by the TileWidth and TileHeight: Tile X = (mouseX - (mouseX mod TileWidth)) / TileWidth Tile Y = (mouseY - (mouseY mod TileHeight)) / TileHeight Which would be the same as doing integer division: Tile X = mouseX / TileWidth Tile Y = mouseY / TileHeight Don't worry, I think this will all make much more sense when you're actually coding the editor. Now we're off to making map files! Saving maps as files As I mentioned in the introduction above, you would normally want to write your map files as binary data to help prevent the average computer user from tampering with your game data. But we're just learning here, so we want to be able to read the map files ourselves and say, "Ahhh! I see, I see!" Also mentioned earlier is that order is very important. The order we save and load our maps is going to be the exact same order in which we draw our tiles. When saving our map to a file, we need a minimum of two things; the map dimensions and then the map data. Here's how we do it: x : integer y : integer Open "/path/to/map.txt" for Output Write MapWidth + "," + MapHeight For x = 0 to MapWidth For y = 0 to Mapheight Write Mapx,y.u + "," + Mapx,y.v + "," + iif(Mapx,y.blocked = True, 1, 0) Next y Next x Close File The iif() is just a nice compact way of doing a conditional on the fly. If your language doesn't support this, use an arbitrary variable to store the number 1 or 0 to represent True and False respectively. And of course you use your own method of specifying a file name to save the file under and such. So now the map file we've written looks something like this (3x3 map to keep it short), with an exception to my comments: 2,2 //This is the map's dimensions. We'll use this for loading the map. 0, 0,0 //Here's the very first tile Map0,0 0,32,1 //This is the tile below it Map0,1 because we go down the entire column 32, 0,0 //before moving to the next x coordinate, which in this case is 1. 32, 0,0 //This is tile Map1,0 because there are only 3 tiles per column as defined 0, 0,1 //at the beginning of the file. You'll notice this is the exact order in 0, 0,0 //which the tiles are drawn, as illustrated above. 0,32,0 //These last 3 tiles are the last column of tiles starting with Map(2,0). 0,32,1 //...Map2,1 32,32,0 //...and Map2,2, the final tile. Which makes sense cause our map is 2x2. Wait a minute, you said the map was 3x3. I never saw a single 3 in the code above! Silly, slap yourself with a trout. We start our counting from 0; 0, 1, and 2. That's three numbers, so we can refer to the map as being 3x3 because it has a width of 3 tiles and height of 3 tiles, which is an area of 9 tiles. Ok, I see that, but what's with the commas (,)? The thing with the commas is that they're delimeters. And a delimeter is how we separate data to make it easier to parse. In this case we use the commas to separate which numbers represent the tile's sX, sY, and bBlocked values respectively. When we parse the file, we read it and use the delimeters to determine which values within the map file go with which variable in the tile structure. Wow, thats so simple I feel bad for not thinking it up myself. Now we're off to loading these maps. Loading our saved maps Loading our maps is the reverse of saving our maps (I know I know, "Here's your sign") except that the order is still kept the same. Meaning that we load the map array up in the same order we saved it in. And now you'll see why we're suppose to keep our map arrays dynamic as explained in the previous tutorial: x : integer y : integer Open "/path/to/map.txt" for Input Read MapWidth, MapHeight Reset Map[] = MapMapWidth,MapHeight // We redimension our array For x = 0 to MapWidth For y = 0 to MapHeight Read Mapx,y.u, Mapx,y.v, Mapx,y.blocked Next y Next x Close File Notice how the tiles are always dealt with in the same order. Also notice how you never run into an EOF (End Of File) error. This is because if you have the correct dimensions it's going to Read just the right amount of tiles everytime. If you are getting an EOF then try looking into the whole starting from 1 instead of 0 problem above. Now you can expand on this. Add more things to the top of the map file, or header, like the name of the map. As you get more advanced with your RPG making skills you'll find that you'll want to add many more things into the header, like a specific music file that plays, the time of day, precipitation, and any other crazy ideas you might come up with. See the forum for any questions not answered or raised in this tutorial about 2D RPG maps. The End. Alternative Binary Maps and Logic Saving data via ASCII characters can cause a map file to become very large. Choosing to use binary data as map data can dramatically reduce size and offer an opportunity for storing more data. See Alternative Binary Maps and Logic